﻿using System.Collections;
using System.Diagnostics;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.LanguageService.Protocol;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     语法节点列表，此列表会在添加时进行排序，成员会按照<see cref="TextPointer" />
///     从小到大进行排序。
/// </summary>
/// <typeparam name="T"></typeparam>
[DebuggerDisplay("{ToDisplayString(),nq}")]
public class SyntaxList<T> : ITextRange, IReadOnlyList<T> where T : ITextRange
{
    private int _count;
    private bool _dirty;
    private T[] _elements;
    private string _text;

    public SyntaxList()
    {
        _elements = new T[8];
        _text = string.Empty;
        Count = 0;
    }

    public bool IsReadOnly => false;


    public T this[int index]
    {
        get
        {
            if (index >= Count || index < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            return _elements[index];
        }
    }


    /// <summary>
    ///     获取当前列表的有效长度
    /// </summary>
    public int Count
    {
        get => _count;

        private set
        {
            _count = value;
            _dirty = true;
        }
    }


    public IEnumerator<T> GetEnumerator()
    {
        return new Enumerator(this);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public TextSpan Span => TextSpan.Create(Uri, Start, Width);

    public int Start => Count == 0 ? 0 : _elements[0].Start;

    public int StartLine => Count == 0 ? 0 : _elements[0].StartLine;

    public int End => Count == 0 ? 0 : _elements[Count - 1].End;

    public int EndLine => Count == 0 ? 0 : _elements[Count - 1].EndLine;

    public int Width => Count == 0 ? 0 : End - Start;

    public string Text => ToString();

    public bool IsEmpty => Count == 0;

    public bool IsComment => false;

    public void Offset(int offset)
    {
        for (int i = 0; i < Count; i++)
        {
            _elements[i].Offset(offset);
        }
    }

    public DocumentUri Uri { get; private set; } = DocumentUri.Empty;

    internal void SetUri(DocumentUri uri)
    {
        Uri = uri;
    }


    /// <summary>
    ///     清空列表
    /// </summary>
    public void Clear()
    {
        Count = 0;
        _elements = new T[8];
    }


    /// <summary>
    ///     移除指定元素，如果指定元素存在，返回<see langword="true" />，否则，
    ///     返回<see langword="false" />。
    /// </summary>
    /// <param name="node"></param>
    public bool Remove(T node)
    {
        int index = Array.IndexOf(_elements, node);

        if (index <= -1)
        {
            return false;
        }

        for (int i = index; i < Count; i++)
        {
            if (i + 1 < _elements.Length)
            {
                _elements[i] = _elements[i + 1];
            }
            else
            {
                _elements[i] = default!;
            }
        }

        --Count;
        return true;
    }


    /// <summary>
    ///     向列表末尾追加一个新的节点。
    /// </summary>
    /// <param name="node">待添加的节点</param>
    public void Add(T node)
    {
        if (Count == 0)
        {
            _elements[0] = node;
            Count++;
        }
        else
        {
            if (_elements[0].Start >= node.End)
            {
                InsertAt(node, 0);
            }
            else if (_elements[Count - 1].End <= node.Start)
            {
                InsertAt(node, Count);
            }
            else
            {
                InsertAt(node, IndexOfPosition(node.Start) + 1);
            }
        }
    }


    /// <summary>
    ///     添加节点列表到此列表中
    /// </summary>
    public void AddRange(IEnumerable<T> nodes)
    {
        foreach (T node in nodes)
        {
            Add(node);
        }
    }


    /// <summary>
    ///     <inheritdoc cref="AddRange(System.Collections.Generic.IEnumerable{T})" />
    /// </summary>
    /// <param name="nodes"></param>
    public void AddRange(Span<T> nodes)
    {
        foreach (T node in nodes)
        {
            Add(node);
        }
    }


    private void InsertAt(T node, int index)
    {
        Debug.Assert(index >= 0);

        // 扩展数组
        if (Count >= _elements.Length)
        {
            T[] array = new T[Count == 0 ? 8 : _elements.Length * 2];

            if (index > 0)
            {
                Array.Copy(_elements, array, index);
            }

            if (index < Count)
            {
                Array.Copy(_elements, index, array, index + 1, Count - index);
            }

            array[index] = node;
            _elements = array;
        }
        else
        {
            if (index < Count)
            {
                int last = Count - index - 1;
                for (int i = Count - 1; i >= last; i--)
                {
                    _elements[i + 1] = _elements[i];
                }
            }

            _elements[index] = node;
        }

        ++Count;
    }


    /// <summary>
    ///     如果列表至少包含一个元素，返回<see langword="true" />。
    /// </summary>
    public bool Any()
    {
        return Count > 0;
    }


    /// <summary>
    ///     如果列表中至少包含一个符合断言函数的元素，返回<see langword="true" />
    /// </summary>
    public bool Any(Predicate<T> predicate)
    {
        for (int i = 0; i < Count; i++)
        {
            if (predicate(_elements[i]))
            {
                return true;
            }
        }

        return false;
    }


    /// <summary>
    ///     如果列表中至少包含一个指定类型的<see cref="ITextNode" />节点，返回<see langword="true" />
    /// </summary>
    public bool Any(SyntaxKinds kind)
    {
        return Any(e => e is ITextNode node && node.IsNode(kind));
    }


    /// <summary>
    ///     获取列表的第一个元素
    /// </summary>
    public T First()
    {
        return _elements[0];
    }


    /// <summary>
    ///     获取第一个元素或<see langword="null" />。
    /// </summary>
    /// <returns></returns>
    public T? FirstOrDefault()
    {
        return Count == 0 ? default : _elements[0];
    }


    /// <summary>
    ///     获取最后一个元素
    /// </summary>
    public T Last()
    {
        return _elements[Count - 1];
    }


    /// <summary>
    ///     获取最后一个元素或<see langword="null" />。
    /// </summary>
    /// <returns></returns>
    public T? LastOrDefault()
    {
        return Count == 0 ? default : _elements[Count - 1];
    }


    /// <summary>
    ///     如果包含指定元素，返回<see langword="true" />
    /// </summary>
    public bool Contains(T value)
    {
        for (int i = 0; i < Count; i++)
        {
            if (value.Equals(_elements[i]))
            {
                return true;
            }
        }

        return false;
    }


    /// <summary>
    ///     查找<paramref name="position" />所在节点的索引，如果没有节点包含此位置，
    ///     返回前一个有效节点的索引。
    /// </summary>
    private int IndexOfPosition(int position)
    {
        if (Count == 0)
        {
            return 0;
        }

        int index = CollectionHelper.BinarySearch(
            _elements, 0, Count, position,
            (node, pos) => node.End - pos);

        if (index < 0)
        {
            index = ~index - 1;
        }

        return index;
    }


    /// <summary>
    ///     从前往后依次查找，返回第一个符合断言函数的对象，如果都不符合，返回<see langword="null" />。
    /// </summary>
    public T? Find(Predicate<T> predicate)
    {
        if (Count <= 0)
        {
            return default;
        }

        for (int i = 0; i < Count; i++)
        {
            T element = _elements[i];

            if (predicate(element))
            {
                return element;
            }
        }

        return default;
    }


    /// <summary>
    ///     在列表中查找包含指定位置的子区间，如果未找到，返回<see langword="null" />。
    /// </summary>
    /// <param name="position">文本位置，0开始</param>
    public T? Find(int position)
    {
        if (Count == 0)
        {
            return default;
        }

        int index = IndexOfPosition(position);

        if (index < 0 || index >= Count)
        {
            return default;
        }

        T child = _elements[index];
        TextSpan childSpan = child.Span;
        if (childSpan.Start >= position && childSpan.Start < position)
        {
            return child;
        }

        return default;
    }


    /// <summary>
    ///     从前到后依次查找，返回第一个符合<paramref name="predicate" />函数的索引，
    ///     如果不存在，返回-1。
    /// </summary>
    public int FindIndex(Predicate<T> predicate)
    {
        for (int i = 0; i < Count; i++)
        {
            if (predicate(_elements[i]))
            {
                return i;
            }
        }

        return -1;
    }


    /// <summary>
    ///     在列表中查找包含指定位置的子区间索引，如果未找到，返回-1。
    /// </summary>
    /// <param name="position">文本位置，0开始</param>
    public int FindIndex(int position)
    {
        if (Count == 0)
        {
            return -1;
        }

        int index = IndexOfPosition(position);

        if (index < 0 || index >= Count)
        {
            return -1;
        }

        T child = _elements[index];
        TextSpan childSpan = child.Span;
        if (childSpan.Start >= position && childSpan.Start < position)
        {
            return index;
        }

        return -1;
    }


    public Span<T> AsSpan()
    {
        return _elements.AsSpan(0, Count);
    }


    public string ToDisplayString()
    {
        return $"Count = {Count}";
    }


    public override string ToString()
    {
        if (Count == 0)
        {
            return string.Empty;
        }

        if (!_dirty)
        {
            return _text;
        }

        return _text = string.Join("\r\n", _elements[..Count]);
    }

    private struct Enumerator(SyntaxList<T> list) : IEnumerator<T>
    {
        private int _index = -1;

        public readonly T Current => list[_index];

        readonly object IEnumerator.Current => list[_index];

        public readonly void Dispose()
        {
        }

        public bool MoveNext()
        {
            ++_index;
            return _index < list.Count;
        }

        public void Reset()
        {
            _index = -1;
        }
    }
}